package agent;

import common.Move;
import common.Piece;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * This class represents a meta search algorithm that simulates the fictitious
 * hands. It is a meta-algorithm because it uses another algorithm (alpha-beta)
 * to work.
 */
public class HandsSimulator extends GameAlgorithm<AgentCurrentState> {

    private AlphaBeta alphaBeta;

    public HandsSimulator() {
        alphaBeta = new AlphaBeta();
    }

    /**
     * This method has two modes of working: 
     * 1) If the agent doesn't know exactly what are the opponent pieces:
     * In this case, the method creates *handsLimit* current fictitious states 
     * (in each of these states, the pieces of the opponent are "guessed").
     * For each of these states its list of successors is generated and the
     * minimaxValues method of the alpha-beta algorithm is called (which receives
     * the successors list). We remember that the minimaxValues method returns
     * the minimax values of each successor.
     * The minimax values obtained by each successor/move in all simulated hands
     * are summed and, at the end, the method returns the move corresponding to
     * the successor that obtained a larger number of minimax values.
     * Notice that, for each current fictitious state, the agent pieces are always
     * the same, which means that the moves that may be played are also the same.
     * 2) If the agent already knows exactly what pieces its opponent has:
     * In this case, an AgentSearchState is built (where the opponent pieces are
     * not guessed), the takeDecision method of alpha-beta is called and the move 
     * that resulted from the search process is returned.
     * @param currentState
     * @return 
     */
    @Override
    public Move takeDecision(AgentCurrentState currentState) {
        //TODO
        //In it its present version it will lead to a NullPointerException if the
        //user chooses the alpha-beta algorithm.
        
        Move move = null;
        //if we do not know the exact opponentPieces
        if (currentState.opponentPossiblePieces.size() > currentState.getNumberOfOpponentPieces()) {
            List<AgentSearchState> possibleHands = new LinkedList<>(currentState.buildGuessedCurrentStates(handsLimit, random));
            //---
            LinkedList<AgentSearchState> sucessor;
            double[] maxValue;
            double bestMoveScore;
            for (AgentSearchState phands : possibleHands) {
                bestMoveScore = Double.NEGATIVE_INFINITY;
                sucessor = (LinkedList<AgentSearchState>) phands.getSucessors();
                maxValue = alphaBeta.minimaxValues(sucessor);
//                phands.move = sucessor.get(0).getMove();
                for (int j = 0; j < maxValue.length; j++){
                    phands.sumMinMaxValue += maxValue[j];
                    if(maxValue[j] > bestMoveScore){
                        phands.move = sucessor.get(j).getMove();
                        bestMoveScore = maxValue[j];
                    }
                }
            }
            //---
            double save = Double.NEGATIVE_INFINITY;
            for (AgentSearchState phands : possibleHands) {
                                                                                System.out.print("sum("+phands.sumMinMaxValue+")\t("+phands.getMove().getPiece().getValue1()+","+phands.getMove().getPiece().getValue2()+") "+phands.getMove().getSide());
                if (phands.sumMinMaxValue > save) {
                    move = phands.getMove();
                                                                                System.out.print(" <--- winner");
                    save = phands.sumMinMaxValue;
                }
                                                                                System.out.println();
            }
                                                                                System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~");
        } else {
            move = alphaBeta.takeDecision(new AgentSearchState(currentState, Player.AGENT));
        }
        return move;
    }

    @Override
    public void setSearchDepth(int depthLimit) {
        alphaBeta.setSearchDepth(depthLimit);
    }
}
